﻿using Devonline.AspNetCore;
using Devonline.Core;
using Microsoft.Extensions.Logging;
using OpenCvSharp;

namespace Devonline.AuxiliaryTools.AITools;

/// <summary>
/// 视频抽帧服务
/// </summary>
public class FramesCaptureService(ILogger<FramesCaptureService> logger, HttpSetting httpSetting) : IFramesCaptureService
{
    private readonly ILogger<FramesCaptureService> _logger = logger;
    private readonly HttpSetting _httpSetting = httpSetting;
    private readonly FileSetting _videoSetting = httpSetting.Attachment.Video;

    /// <summary>
    /// 从视频种捕获图片
    /// </summary>
    /// <param name="fileName">原始视频文件名</param>
    /// <param name="captureCount">捕获数量</param>
    /// <returns></returns>
    public string[]? Capture(string fileName, int captureCount = AppSettings.UNIT_ONE)
    {
        if (!File.Exists(fileName))
        {
            _logger.LogInformation($"文件 [{fileName}] 不存在!");
            return default;
        }

        var filePath = Path.GetDirectoryName(fileName);
        if (!Directory.Exists(filePath))
        {
            _logger.LogInformation($"文件夹 [{filePath}] 不存在!");
            return default;
        }

        var extension = Path.GetExtension(fileName);
        var limitedExtensions = _videoSetting.Extensions.Split(AppSettings.CHAR_COMMA, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        if (!limitedExtensions.Any(x => x == extension.ToUpperInvariant()))
        {
            _logger.LogInformation($"文件类型 [{extension}] 不是允许的视频文件!");
            return default;
        }

        using var videoCapture = new VideoCapture(fileName);
        if (!videoCapture.IsOpened())
        {
            _logger.LogInformation($"文件 [{fileName}] 打开失败!");
            return default;
        }

        //帧率
        var frameRate = Convert.ToInt32(videoCapture.Fps);
        //视频时长, 单位: 秒
        var duration = videoCapture.FrameCount / frameRate;
        //取帧间隔
        var interval = (captureCount == AppSettings.UNIT_ONE ? AppSettings.UNIT_ONE : (int)(duration / captureCount)) * frameRate;
        _logger.LogInformation($"文件 [{fileName}] 抽帧处理 (帧率: {frameRate} / 抽帧间隔: {interval} 帧)");

        var index = 0;
        int framePosition = 0;
        var paddingLength = captureCount.ToString().Length;
        var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName)! + AppSettings.CHAR_UNDERLINE;
        var random = new Random(DateTime.Now.Microsecond);
        var outputFiles = new List<string>();
        while (index < captureCount)
        {
            framePosition = random.Next(AppSettings.UNIT_ZERO, interval) + index * interval;
            videoCapture.PosFrames = framePosition;
            using var processedFrame = new Mat();
            if (videoCapture.Read(processedFrame))
            {
                try
                {
                    var outputFileName = Path.Combine(filePath, fileNameWithoutExtension + index.ToString().PadLeft(paddingLength, AppSettings.CHAR_ZERO) + AppSettings.DEFAULT_IMAGE_FILE_EXTENSION);
                    if (Cv2.ImWrite(outputFileName, processedFrame))
                    {
                        _logger.LogInformation($"文件 [{fileName}] 第 {index} 次抽帧, 已抽取第 {framePosition} 帧, 保存为文件: {outputFileName}");
                    }

                    outputFiles.Add(outputFileName);
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, $"文件 [{fileName}] 抽帧异常, 详情: " + ex.GetMessage());
                    return default;
                }
            }

            index++;
        }

        return outputFiles.ToArray();
    }
}